/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.andtinder.view;

import ohos.agp.components.*;
import ohos.agp.database.DataSetSubscriber;
import ohos.agp.utils.Point;
import ohos.app.Context;

public class CardContainer extends BaseCardAdapterView {
    protected static final float rotationDegrees = 15.0f;

    private BaseItemProvider mAdapter;
    private int lastObjectInStack = 0;
    private onFlingListener mFlingListener;
    private AdapterDataSetObserver mDataSetObserver;
    private boolean mInLayout = false;
    private Component mActiveCard = null;
    private SwipeCardListener flingCardListener;
    private Point mLastTouchPoint;

    /**
     * constructor
     *
     * @param context
     */
    public CardContainer(Context context) {
        this(context, null);
    }

    /**
     * constructor
     *
     * @param context
     * @param attrSet
     */
    public CardContainer(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    /**
     * constructor
     *
     * @param context
     * @param attrSet
     * @param styleName
     */
    public CardContainer(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
    }

    /**
     * A shortcut method to set both the listeners and the adapter.
     *
     * @param context The activity context which extends onFlingListener, OnItemClickListener or both
     * @param mAdapter The adapter you have to set.
     * @throws RuntimeException if context not instanceof onFlingListener
     */
    public void init(final Context context, BaseItemProvider mAdapter) {
        if (context instanceof onFlingListener) {
            mFlingListener = (onFlingListener) context;
        } else {
            throw new RuntimeException("ability does not implement SwipeFlingAdapterView.onFlingListener");
        }
        setItemProvider(mAdapter);
    }

    @Override
    public Component getSelectedComponent() {
        return mActiveCard;
    }

    @Override
    public void postLayout() {
        if (!mInLayout) {
            super.postLayout();
        }
    }

    @Override
    public void onRefreshed(Component component) {
        // if we don't have an adapter, we don't need to do anything
        if (mAdapter == null) {
            return;
        }
        mInLayout = true;
        Component topCard = getComponentAt(lastObjectInStack);
        if (topCard != null && topCard.equals(mActiveCard)) {
            if (this.flingCardListener.isTouching()) {
                Point lastPoint = this.flingCardListener.getLastPoint();
                if (this.mLastTouchPoint == null || !this.mLastTouchPoint.equals(lastPoint)) {
                    this.mLastTouchPoint = lastPoint;
                    removeComponents(0, lastObjectInStack);
                }
            }
        } else {
            setTopView();
        }
        mInLayout = false;
    }

    /**
     * Set the top view and add the fling listener
     */
    private void setTopView() {
        if (getChildCount() > 0) {
            mActiveCard = getComponentAt(lastObjectInStack);
            if (mActiveCard != null) {
                flingCardListener = new SwipeCardListener(
                        this,
                        mActiveCard,
                        mAdapter.getItem(0),
                        rotationDegrees,
                        new SwipeCardListener.FlingListener() {
                            @Override
                            public void onCardExited() {
                                mActiveCard = null;
                                mFlingListener.removeFirstObjectInAdapter();
                            }

                            @Override
                            public void onClick(Object dataObject) {
                                mFlingListener.onCardClick(dataObject);
                            }

                            @Override
                            public void leftExit(Object dataObject) {
                                mFlingListener.onLeftCardExit(dataObject);
                            }

                            @Override
                            public void rightExit(Object dataObject) {
                                mFlingListener.onRightCardExit(dataObject);
                            }
                        });
                mActiveCard.setTouchEventListener(flingCardListener);
            }
        }
    }

    @Override
    public BaseItemProvider getItemProvider() {
        return mAdapter;
    }

    @Override
    public void setItemProvider(BaseItemProvider provider) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.removeDataSubscriber(mDataSetObserver);
            mDataSetObserver = null;
        }
        mAdapter = provider;
        if (mAdapter != null && mDataSetObserver == null) {
            mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.addDataSubscriber(mDataSetObserver);
        }
        super.setItemProvider(provider);
    }

    public void setFlingListener(onFlingListener onFlingListener) {
        this.mFlingListener = onFlingListener;
    }

    @Override
    public ComponentContainer.LayoutConfig createLayoutConfig(Context context, AttrSet attrSet) {
        return new StackLayout.LayoutConfig(context, attrSet);
    }

    /**
     * The observer
     */
    private class AdapterDataSetObserver extends DataSetSubscriber {
        @Override
        public void onChanged() {
            postLayout();
        }

        @Override
        public void onInvalidated() {
            postLayout();
        }
    }

    public interface OnItemClickListener {
        /**
         * do something if the item onclicker
         *
         * @param itemPosition
         * @param dataObject
         */
        void onItemClicked(int itemPosition, Object dataObject);
    }

    public interface onFlingListener {
        /**
         * remove FirstObject In Adapter
         */
        void removeFirstObjectInAdapter();

        /**
         * on left card exit
         *
         * @param dataObject
         */
        void onLeftCardExit(Object dataObject);

        /**
         * on right card exit
         *
         * @param dataObject
         */
        void onRightCardExit(Object dataObject);

        /**
         * on click
         *
         * @param dataObject
         */
        void onCardClick(Object dataObject);
    }

    /**
     * setNotNeedRotation
     */
    public void setNotNeedRotation() {
        flingCardListener.setNeedRotation(false);
    }
}
